package com.xing.stream;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@FunctionalInterface
public interface StreamFn<T, R> {

    Stream<R> apply(Stream<T> t);

    default <V> StreamFn<T, V> map(Function<R, V> func) {
        return (Stream<T> s) -> apply(s).map(func);
    }

    default StreamFn<T, R> filter(Predicate<R> func) {
        return (Stream<T> s) -> apply(s).filter(func);
    }

    default Optional<R> first(Collection<T> s) {
        return apply(s.stream()).findFirst();
    }

    default List<R> listOn(Collection<T> s) {
        return apply(s.stream()).collect(Collectors.toList());
    }

    static <T, R> StreamFn<T, R> of(Function<T, R> func) {
        return (Stream<T> s) -> s.map(func);
    }

    static <T> StreamFn<T, T> of(Predicate<T> predicate) {
        return (Stream<T> s) -> s.filter(predicate);
    }

    static <E, R> List<R> doMap(Collection<E> collection, Function<E, R> func) {
        return of(func).listOn(collection);
    }

    static <E> List<E> doFilter(Collection<E> collection, Predicate<E> func) {
        return of(func).listOn(collection);
    }
}
